﻿using System;
using Microsoft.SharePoint;
using System.IO;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.Xml.XPath;
using ServBus.ListForm2013.Utility;
using System.Diagnostics;

namespace ServBus.ListForm2013.SPFieldChangeEvent
{
    /// <summary>
    /// Main List Events
    /// </summary>
    public class SPFieldChangeEvent : SPListEventReceiver
    {
        /// <summary>
        /// A field was added.
        /// </summary>
        public override void FieldAdded(SPListEventProperties properties)
        {
            try
            {
                base.FieldAdded(properties);
                string fieldName = properties.FieldName;
                Dictionary<string, string> _targetXSDFiles = ExtractXSD(properties.Web, properties.Field);
                foreach (string xsdURL in _targetXSDFiles.Keys)
                {
                    string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\myschema.xsd";
                    if (!CheckFieldExist(fieldName, xsdTempLoaction))
                    {
                        AddFieldsRefInMyFields(fieldName, xsdTempLoaction);
                        AddFieldDefinRootElement(properties.Field, xsdTempLoaction);

                        string listFile = CreateListFile(_targetXSDFiles[xsdURL]);
                        string cmdString = "makecab /F list.txt";
                        string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
                        UploadXSN(properties.Web, xsdURL, _targetXSDFiles[xsdURL]);
                    }
                }
            }
            catch (Exception ex)
            {
                string error_message = DateTime.Now.ToShortDateString() + "--:--" + ex.ToString();
                ExceptionLog(error_message);
            }
        }

        /// <summary>
        /// A field was deleting.
        /// </summary>
        public override void FieldDeleting(SPListEventProperties properties)
        {
            try
            {
                base.FieldDeleting(properties);
                string fieldName = properties.FieldName;
                Dictionary<string, string> _targetXSDFiles = ExtractXSD(properties.Web, properties.Field);
                foreach (string xsdURL in _targetXSDFiles.Keys)
                {
                    string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\myschema.xsd";
                    if (CheckFieldExist(fieldName, xsdTempLoaction))
                    {
                        DeleteFieldsRefInMyFields(fieldName, xsdTempLoaction);
                        DeleteFieldDefinRootElement(fieldName, xsdTempLoaction);

                        string listFile = CreateListFile(_targetXSDFiles[xsdURL]);
                        string cmdString = "makecab /F list.txt";
                        string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
                        UploadXSN(properties.Web, xsdURL, _targetXSDFiles[xsdURL]);
                    }
                }
            }
            catch (Exception ex)
            {
                string error_message = DateTime.Now.ToShortDateString() + "--:--" + ex.ToString();
                ExceptionLog(error_message);
            }
        }

        /// <summary>
        /// A field was updated.
        /// </summary>
        public override void FieldUpdated(SPListEventProperties properties)
        {
            try
            {
                base.FieldUpdated(properties);
                string fieldName = properties.FieldName;
                Dictionary<string, string> _targetXSDFiles = ExtractXSD(properties.Web, properties.Field);
                foreach (string xsdURL in _targetXSDFiles.Keys)
                {
                    string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\myschema.xsd";
                    if (CheckFieldExist(fieldName, xsdTempLoaction))
                    {
                        UpdateFieldDefinRootElement(properties.FieldName, properties.Field.Title, xsdTempLoaction);

                        string listFile = CreateListFile(_targetXSDFiles[xsdURL]);
                        string cmdString = "makecab /F list.txt";
                        string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
                        UploadXSN(properties.Web, xsdURL, _targetXSDFiles[xsdURL]);
                    }
                }
            }
            catch (Exception ex)
            {
                string error_message = DateTime.Now.ToShortDateString() + "--:--" + ex.ToString();
                ExceptionLog(error_message);
            }
        }

        private List<string> GetXSDFieldList(string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            List<string> xsdFieldList = new List<string>();
            XmlNamespaceManager xmlNM = new XmlNamespaceManager(xsdDoc.NameTable);
            xmlNM.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XmlNodeList xsdFields = xsdDoc.SelectNodes("/xsd:schema/xsd:element", xmlNM);

            foreach (XmlNode xsdField in xsdFields)
            {
                if (!xsdField.Attributes["name"].Value.Equals("myFields"))
                {
                    xsdFieldList.Add(xsdField.Attributes["name"].Value);
                }
            }

            return xsdFieldList;
        }

        private bool CheckFieldExist(string fieldName, string xsdDocPath)
        {
            bool result = false;
            List<string> fieldList = GetXSDFieldList(xsdDocPath);
            if (fieldList.Contains(fieldName))
            {
                result = true;
            }

            return result;
        }

        private void AddFieldsRefInMyFields(string fieldName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            string xmlStr = "<xsd:element xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ref=\"my:" + fieldName + "\"" + " minOccurs=\"0\" maxOccurs=\"1\"/>";
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            XPathNavigator myFieldIt = xNav.SelectSingleNode("/xsd:schema/xsd:element[@name='myFields']/xsd:complexType/xsd:sequence", manager);
            myFieldIt.AppendChild(xmlStr);
            xsdDoc.Save(xsdDocPath);
        }

        private void AddFieldDefinRootElement(SPField spField, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            XPathNavigator myFieldIt = xNav.SelectSingleNode("/xsd:schema", manager);

            string str = string.Empty;
            #region SPFieldMapping
            switch (spField.Type)
            {
                case SPFieldType.Text:
                    str = string.Format(BaseTypeStrings.singleText, spField.InternalName, spField.Title);
                    break;
                case SPFieldType.Number:
                    str = string.Format(BaseTypeStrings.number, spField.InternalName, spField.Title);
                    break;
                case SPFieldType.Currency:
                    str = string.Format(BaseTypeStrings.currency, spField.InternalName, spField.Title);
                    break;
                case SPFieldType.Lookup:
                    SPFieldLookup lkpFld = spField as SPFieldLookup;
                    string lkpFldListName = lkpFld.ParentList.ParentWeb.Lists[new Guid(lkpFld.LookupList)].Title;
                    str = "<xsd:element ma:displayName=\"" + spField.Title
                        + "\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" name=\"{0}\" "
                        + "type=\"xsd:positiveInteger\" ma:auxDataSourceName=\"{1}\" "
                        + "ma:auxChoicesXPath=\"/dfs:myFields/dfs:dataFields/d:SharePointListItem_RW\" "
                        + "ma:auxValue=\"d:ID\" ma:auxDisplay=\"d:{2}\" "
                        + "nillable=\"true\" "
                        + "xmlns:ma=\"http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes\" />";
                    str = string.Format(str, spField.InternalName, lkpFldListName, lkpFld.LookupField);
                    break;

                case SPFieldType.DateTime:
                    SPFieldDateTime dateTimeField = (SPFieldDateTime)spField;
                    if (dateTimeField.DisplayFormat.Equals(SPDateTimeFieldFormatType.DateOnly))
                    {
                        str = string.Format(BaseTypeStrings.dateonly, spField.InternalName, spField.Title);
                    }
                    else
                    {
                        str = string.Format(BaseTypeStrings.datetime, spField.InternalName, spField.Title);
                    }
                    break;

                case SPFieldType.Calculated:
                    break;

                case SPFieldType.Boolean:
                    str = string.Format(BaseTypeStrings.boolean, spField.InternalName, spField.Title);
                    break;

                case SPFieldType.Counter:
                    break;

                case SPFieldType.URL:
                    SPFieldUrl urlField = (SPFieldUrl)spField;
                    if (urlField.DisplayFormat.Equals(SPUrlFieldFormatType.Hyperlink))
                    {
                        str = string.Format(BaseTypeStrings.url, spField.InternalName, spField.Title);
                    }
                    else
                    {
                        str = string.Format(BaseTypeStrings.url, spField.InternalName, spField.Title);
                    }
                    break;

                case SPFieldType.User:
                    str = string.Format(BaseTypeStrings.userType, spField.InternalName, spField.Title);
                    break;

                case SPFieldType.Note:
                    str = string.Format(BaseTypeStrings.multiText, spField.InternalName, spField.Title);
                    break;

                case SPFieldType.Choice:
                    str = string.Format(BaseTypeStrings.DropdownToSchema, BaseTypeStrings.DropdownDataSouceName, spField.InternalName, spField.Title);
                    break;

                case SPFieldType.MultiChoice:
                    str = string.Format(BaseTypeStrings.MultiDropdownToSchema1, spField.InternalName, spField.Title);
                    break;

                default:
                    break;
            }

            #endregion
            myFieldIt.AppendChild(str);
            xsdDoc.Save(xsdDocPath);
        }

        private void DeleteFieldsRefInMyFields(string fieldName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            string xPath = string.Format("/xsd:schema/xsd:element[@name='myFields']/xsd:complexType/xsd:sequence/xsd:element[@ref='my:{0}']", fieldName);
            XPathNavigator myFieldIt = xNav.SelectSingleNode(xPath, manager);
            myFieldIt.DeleteSelf();
            xsdDoc.Save(xsdDocPath);
        }

        private void DeleteFieldDefinRootElement(string fieldName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            string xPath = string.Format("/xsd:schema/xsd:element[@name='{0}']", fieldName);
            XPathNavigator myFieldIt = xNav.SelectSingleNode(xPath, manager);
            myFieldIt.DeleteSelf();
            xsdDoc.Save(xsdDocPath);
        }

        private void UpdateFieldDefinRootElement(string fieldName, string displayName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            manager.AddNamespace("ma", "http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            string xPath = string.Format("/xsd:schema/xsd:element[@name='{0}']/@ma:displayName", fieldName);
            XPathNavigator myFieldIt = xNav.SelectSingleNode(xPath, manager);
            myFieldIt.SetValue(displayName);
            xsdDoc.Save(xsdDocPath);
        }

        private Dictionary<string, string> ExtractXSD(SPWeb Web, SPField Field)
        {
            Dictionary<string, string> _targetXSDFiles = new Dictionary<string, string>();
            //Get ContentType
            SPContentTypeCollection _cTypes = Field.ParentList.ContentTypes;
            foreach (SPContentType cType in _cTypes)
            {
                if (cType.Fields.Contains(Field.Id))
                {
                    string xsdURL = Field.ParentList.RootFolder.ServerRelativeUrl + "/" + cType.ResourceFolder.Name + "/template.xsn";
                    string xsdTemp = @"C:\TempXsnFiles\" + cType.Id.ToString();
                    SPFile m_file = Web.GetFile(xsdURL);
                    if (m_file.Exists)
                    {
                        //Get XSN File Temp Location
                        _targetXSDFiles.Add(xsdURL, xsdTemp);
                        //Move XSD To Temp Location
                        int size = 10 * 1024;
                        using (Stream stream = m_file.OpenBinaryStream())
                        {
                            Directory.CreateDirectory(xsdTemp);
                            string xsdTempLoaction = xsdTemp + "\\template.xsn";
                            using (FileStream fs = new FileStream(xsdTempLoaction, FileMode.Create, FileAccess.Write))
                            {
                                byte[] xsd_content = m_file.OpenBinary();
                                int nBytesRead = 0;
                                while ((nBytesRead = stream.Read(xsd_content, 0, xsd_content.Length)) > 0)
                                {
                                    fs.Write(xsd_content, 0, nBytesRead);
                                }
                            }
                        }

                    }
                }
            }

            foreach (string xsdURL in _targetXSDFiles.Keys)
            {
                //Unpack XSN to local
                string xsdTemp = _targetXSDFiles[xsdURL];
                string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\template.xsn";
                string cmdString = string.Format("expand \"{0}\" \"{1}\" -f:*", xsdTempLoaction, xsdTemp);
                string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
            }

            return _targetXSDFiles;
            //Replace xsd file
            //Package and Upload
        }

        private string RunCommand(string cmdString, string xsdDictory)
        {
            Process p = new Process();
            //启动DOS程序
            p.StartInfo.WorkingDirectory = xsdDictory;
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;//不用Shell启动
            p.StartInfo.RedirectStandardInput = true;//重定向输入
            p.StartInfo.RedirectStandardOutput = true;//重定向输出
            p.StartInfo.CreateNoWindow = true;//不显示窗口
            p.Start();//开始进程
            p.StandardInput.WriteLine(cmdString);// 向cmd.exe输入command
            p.StandardInput.WriteLine("exit");//结束
            p.WaitForExit(60000);//等等执行完成
            string outPutString = p.StandardOutput.ReadToEnd();// 得到cmd.exe的输出
            p.Close();
            return outPutString;
        }

        private void ExceptionLog(string errorMessage)
        {
            using (FileStream fs = new FileStream("c:\\sp_event_log.txt", FileMode.Append, FileAccess.Write))
            {
                using (StreamWriter swt = new StreamWriter(fs, System.Text.Encoding.GetEncoding("utf-8")))
                {
                    swt.WriteLine(errorMessage);
                }
            }
        }

        private string CreateListFile(string xsdTemp)
        {
            try
            {
                string listFilePath = Path.Combine(xsdTemp, "list.txt");
                string listContent = string.Empty;//文件内容
                listContent += ";*** Sample Source Code MakeCAB Directive file example \r\n"
                            + ";\r\n"
                            + ".OPTION EXPLICIT ; Generate errors\r\n "
                            + ".Set CabinetNameTemplate=template_xsn\r\n"
                            + ".set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory\r\n"
                            + ".Set CompressionType=MSZIP;** All files are compressed in cabinet files\r\n"
                            + ".Set UniqueFiles=\"OFF\"\r\n"
                            + ".Set Cabinet=on\r\n"
                            + ".Set DiskDirectory1=test\r\n"
                            + ";*** <the end>\r\n";
                DirectoryInfo xsdTempDI = new DirectoryInfo(xsdTemp);
                FileInfo[] fileInfos = xsdTempDI.GetFiles();
                foreach (FileInfo fileInfo in fileInfos)
                {
                    if (fileInfo.Name != "template.xsn" && fileInfo.Name != "list.txt")
                    {
                        listContent += string.Format("\"{0}\" \r\n", fileInfo.Name);
                    }
                }
                using (FileStream fs = new FileStream(listFilePath, FileMode.Create, FileAccess.Write))
                {
                    using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                    {
                        sw.Write(listContent);
                        sw.Flush();
                    }
                }

                return listFilePath;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private void UploadXSN(SPWeb Web, string FileUrl, string XSNLocation)
        {
            Web.Files.Add(FileUrl, GetXsnFileStream(XSNLocation + "\\test\\template_xsn"), true);
        }

        private byte[] GetXsnFileStream(string XSNLocation)
        {
            byte[] buf = new byte[100];
            List<byte> bytes = new List<byte>();
            using (FileStream fs = File.Open(XSNLocation, FileMode.Open, FileAccess.Read))
            {
                int offset = 0;
                int len = 0;
                while ((len = fs.Read(buf, offset, buf.Length)) > 0)
                {
                    CopyOneStreamToStream(buf, bytes);
                    buf = new byte[100];
                }
            }

            return bytes.ToArray();
        }

        private void CopyOneStreamToStream(byte[] byte1, List<byte> byte2)
        {
            foreach (byte bt in byte1)
            {
                byte2.Add(bt);
            }
        }
    }

    /// <summary>
    /// LKP List Events
    /// </summary>
    public class LKPSPFieldChangeEvent : SPListEventReceiver
    {
        /// <summary>
        /// A field was added.
        /// </summary>
        public override void FieldAdded(SPListEventProperties properties)
        {
            try
            {
                base.FieldAdded(properties);
                string fieldName = properties.FieldName;
                //Check ContentType
                SPContentTypeCollection mCTypes = properties.Field.ParentList.ContentTypes;
                foreach (SPContentType mCType in mCTypes)
                {
                    if (mCType.Fields.Contains(properties.Field.Id))
                    {
                        SPList configList = properties.Web.Lists[Constants.LookupForm_Config_NAME];
                        SPQuery query = new SPQuery
                        {
                            Query =
                                "<Where><And><Contains><FieldRef Name='sTitle' /><Value Type='Text'>" + properties.ListId +
                                "</Value></Contains><Contains><FieldRef Name='sContentType' /><Value Type='Text'>" + mCType.Id +
                                "</Value></Contains></And></Where>"
                        };
                        SPListItemCollection mListItems = configList.GetItems(query);
                        foreach (SPListItem mListItem in mListItems)
                        {
                            string mListId = Convert.ToString(mListItem["Title"]);
                            string mContentTypeId = Convert.ToString(mListItem["mContentType"]);
                            SPList mList = properties.Web.Lists[new Guid(mListId)];
                            SPContentType mContentType = mList.ContentTypes[new SPContentTypeId(mContentTypeId)];
                            string UniqueName = string.Format("{0}_{1}_{2}", properties.ListTitle, mCType.Name, properties.Field.InternalName).Replace(" ", "_");
                            string cTypeUName = string.Format("{0}_{1}", properties.ListTitle, mCType.Name).Replace(" ", "_");

                            Dictionary<string, string> _targetXSDFiles = ExtractXSD(properties.Web, mContentType);
                            foreach (string xsdURL in _targetXSDFiles.Keys)
                            {
                                string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\myschema.xsd";
                                if (!CheckFieldExist(UniqueName, xsdTempLoaction))
                                {
                                    AddFieldsRefInMyFields(cTypeUName, UniqueName, xsdTempLoaction);
                                    AddFieldDefinRootElement(properties.Field, xsdTempLoaction, UniqueName);

                                    string listFile = CreateListFile(_targetXSDFiles[xsdURL]);
                                    string cmdString = "makecab /F list.txt";
                                    string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
                                    UploadXSN(properties.Web, xsdURL, _targetXSDFiles[xsdURL]);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string error_message = DateTime.Now.ToShortDateString() + "--:--" + ex.ToString();
                ExceptionLog(error_message);
            }
        }

        /// <summary>
        /// A field was deleting.
        /// </summary>
        public override void FieldDeleting(SPListEventProperties properties)
        {
            try
            {
                base.FieldDeleting(properties);
                string fieldName = properties.FieldName;
                //Check ContentType
                SPContentTypeCollection mCTypes = properties.Field.ParentList.ContentTypes;
                foreach (SPContentType mCType in mCTypes)
                {
                    if (mCType.Fields.Contains(properties.Field.Id))
                    {
                        SPList configList = properties.Web.Lists[Constants.LookupForm_Config_NAME];
                        SPQuery query = new SPQuery
                        {
                            Query =
                                "<Where><And><Contains><FieldRef Name='sTitle' /><Value Type='Text'>" + properties.ListId +
                                "</Value></Contains><Contains><FieldRef Name='sContentType' /><Value Type='Text'>" + mCType.Id +
                                "</Value></Contains></And></Where>"
                        };
                        SPListItemCollection mListItems = configList.GetItems(query);
                        foreach (SPListItem mListItem in mListItems)
                        {
                            string mListId = Convert.ToString(mListItem["Title"]);
                            string mContentTypeId = Convert.ToString(mListItem["mContentType"]);
                            SPList mList = properties.Web.Lists[new Guid(mListId)];
                            SPContentType mContentType = mList.ContentTypes[new SPContentTypeId(mContentTypeId)];
                            string UniqueName = string.Format("{0}_{1}_{2}", properties.ListTitle, mCType.Name, properties.Field.InternalName).Replace(" ", "_");
                            string cTypeUName = string.Format("{0}_{1}", properties.ListTitle, mCType.Name).Replace(" ", "_");
        
                            Dictionary<string, string> _targetXSDFiles = ExtractXSD(properties.Web, mContentType);
                            foreach (string xsdURL in _targetXSDFiles.Keys)
                            {
                                string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\myschema.xsd";
                                if (CheckFieldExist(UniqueName, xsdTempLoaction))
                                {
                                    DeleteFieldsRefInMyFields(cTypeUName, xsdTempLoaction);
                                    DeleteFieldDefinRootElement(UniqueName, xsdTempLoaction);

                                    string listFile = CreateListFile(_targetXSDFiles[xsdURL]);
                                    string cmdString = "makecab /F list.txt";
                                    string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
                                    UploadXSN(properties.Web, xsdURL, _targetXSDFiles[xsdURL]);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string error_message = DateTime.Now.ToShortDateString() + "--:--" + ex.ToString();
                ExceptionLog(error_message);
            }
        }

        /// <summary>
        /// A field was updated.
        /// </summary>
        public override void FieldUpdated(SPListEventProperties properties)
        {
            try
            {
                base.FieldUpdated(properties);
                string fieldName = properties.FieldName;
                //Check ContentType
                SPContentTypeCollection mCTypes = properties.Field.ParentList.ContentTypes;
                foreach (SPContentType mCType in mCTypes)
                {
                    if (mCType.Fields.Contains(properties.Field.Id))
                    {
                        SPList configList = properties.Web.Lists[Constants.LookupForm_Config_NAME];
                        SPQuery query = new SPQuery
                        {
                            Query =
                                "<Where><And><Contains><FieldRef Name='sTitle' /><Value Type='Text'>" + properties.ListId +
                                "</Value></Contains><Contains><FieldRef Name='sContentType' /><Value Type='Text'>" + mCType.Id +
                                "</Value></Contains></And></Where>"
                        };
                        SPListItemCollection mListItems = configList.GetItems(query);
                        foreach (SPListItem mListItem in mListItems)
                        {
                            string mListId = Convert.ToString(mListItem["Title"]);
                            string mContentTypeId = Convert.ToString(mListItem["mContentType"]);
                            SPList mList = properties.Web.Lists[new Guid(mListId)];
                            SPContentType mContentType = mList.ContentTypes[new SPContentTypeId(mContentTypeId)];
                            string UniqueName = string.Format("{0}_{1}_{2}", properties.ListTitle, mCType.Name, properties.Field.InternalName).Replace(" ", "_");
                            string cTypeUName = string.Format("{0}_{1}", properties.ListTitle, mCType.Name).Replace(" ", "_");
       
                            Dictionary<string, string> _targetXSDFiles = ExtractXSD(properties.Web, mContentType);
                            foreach (string xsdURL in _targetXSDFiles.Keys)
                            {
                                string xsdTempLoaction = _targetXSDFiles[xsdURL] + "\\myschema.xsd";
                                if (CheckFieldExist(UniqueName, xsdTempLoaction))
                                {
                                    UpdateFieldDefinRootElement(UniqueName, properties.Field.Title,
                                        xsdTempLoaction);

                                    string listFile = CreateListFile(_targetXSDFiles[xsdURL]);
                                    string cmdString = "makecab /F list.txt";
                                    string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);
                                    UploadXSN(properties.Web, xsdURL, _targetXSDFiles[xsdURL]);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string error_message = DateTime.Now.ToShortDateString() + "--:--" + ex.ToString();
                ExceptionLog(error_message);
            }
        }

        #region Obsolete

        static string mockXSDDocPath = @"C:\TempXsnFiles\28f8a8d4-e4bd-4af2-8465-845a583716e3\myschema.xsd";
        private XmlDocument MockXSDDocument()
        {
            XmlDocument xsdDoc = new XmlDocument();

            string content = File.ReadAllText(mockXSDDocPath, Encoding.UTF8);
            xsdDoc.LoadXml(content);

            return xsdDoc;
        }
        #endregion

        private List<string> GetXSDFieldList(string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            List<string> xsdFieldList = new List<string>();
            XmlNamespaceManager xmlNM = new XmlNamespaceManager(xsdDoc.NameTable);
            xmlNM.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XmlNodeList xsdFields = xsdDoc.SelectNodes("/xsd:schema/xsd:element", xmlNM);

            foreach (XmlNode xsdField in xsdFields)
            {
                if (!xsdField.Attributes["name"].Value.Equals("myFields"))
                {
                    xsdFieldList.Add(xsdField.Attributes["name"].Value);
                }
            }

            return xsdFieldList;
        }

        private bool CheckFieldExist(string fieldName, string xsdDocPath)
        {
            bool result = false;
            List<string> fieldList = GetXSDFieldList(xsdDocPath);
            if (fieldList.Contains(fieldName))
            {
                result = true;
            }

            return result;
        }

        private void AddFieldsRefInMyFields(string sNodeName, string uniqueName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            string xmlStr = "<xsd:element xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" ref=\"my:" + uniqueName + "\"" + " minOccurs=\"0\" maxOccurs=\"1\"/>";
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            XPathNavigator myFieldIt = xNav.SelectSingleNode("/xsd:schema/xsd:element[@name='" + sNodeName + "']/xsd:complexType/xsd:sequence", manager);
            myFieldIt.AppendChild(xmlStr);
            xsdDoc.Save(xsdDocPath);
        }

        private void AddFieldDefinRootElement(SPField spField, string xsdDocPath, string uniqueName)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            XPathNavigator myFieldIt = xNav.SelectSingleNode("/xsd:schema", manager);

            string str = string.Empty;
            #region SPFieldMapping
            switch (spField.Type)
            {
                case SPFieldType.Text:
                    str = string.Format(BaseTypeStrings.singleText, uniqueName, spField.Title);
                    break;
                case SPFieldType.Number:
                    str = string.Format(BaseTypeStrings.number, uniqueName, spField.Title);
                    break;
                case SPFieldType.Currency:
                    str = string.Format(BaseTypeStrings.currency, uniqueName, spField.Title);
                    break;
                case SPFieldType.Lookup:
                    SPFieldLookup lkpFld = spField as SPFieldLookup;
                    string lkpFldListName = lkpFld.ParentList.ParentWeb.Lists[new Guid(lkpFld.LookupList)].Title;
                    str = "<xsd:element ma:displayName=\"" + spField.Title
                        + "\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" name=\"{0}\" "
                        + "type=\"xsd:positiveInteger\" ma:auxDataSourceName=\"{1}\" "
                        + "ma:auxChoicesXPath=\"/dfs:myFields/dfs:dataFields/d:SharePointListItem_RW\" "
                        + "ma:auxValue=\"d:ID\" ma:auxDisplay=\"d:{2}\" "
                        + "nillable=\"true\" "
                        + "xmlns:ma=\"http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes\" />";
                    str = string.Format(str, uniqueName, lkpFldListName, lkpFld.LookupField);
                    break;

                case SPFieldType.DateTime:
                    SPFieldDateTime dateTimeField = (SPFieldDateTime)spField;
                    if (dateTimeField.DisplayFormat.Equals(SPDateTimeFieldFormatType.DateOnly))
                    {
                        str = string.Format(BaseTypeStrings.dateonly, uniqueName, spField.Title);
                    }
                    else
                    {
                        str = string.Format(BaseTypeStrings.datetime, uniqueName, spField.Title);
                    }
                    break;

                case SPFieldType.Calculated:
                    break;

                case SPFieldType.Boolean:
                    str = string.Format(BaseTypeStrings.boolean, uniqueName, spField.Title);
                    break;

                case SPFieldType.Counter:
                    break;

                case SPFieldType.URL:
                    SPFieldUrl urlField = (SPFieldUrl)spField;
                    if (urlField.DisplayFormat.Equals(SPUrlFieldFormatType.Hyperlink))
                    {
                        str = string.Format(BaseTypeStrings.url, uniqueName, spField.Title);
                    }
                    else
                    {
                        str = string.Format(BaseTypeStrings.url, uniqueName, spField.Title);
                    }
                    break;

                case SPFieldType.User:
                    str = string.Format(BaseTypeStrings.userType, uniqueName, spField.Title);
                    break;

                case SPFieldType.Note:
                    str = string.Format(BaseTypeStrings.multiText, uniqueName, spField.Title);
                    break;

                case SPFieldType.Choice:
                    str = string.Format(BaseTypeStrings.DropdownToSchema, BaseTypeStrings.DropdownDataSouceName, uniqueName, spField.Title);
                    break;

                case SPFieldType.MultiChoice:
                    str = string.Format(BaseTypeStrings.MultiDropdownToSchema1, uniqueName, spField.Title);
                    break;

                default:
                    break;
            }

            #endregion
            myFieldIt.AppendChild(str);
            xsdDoc.Save(xsdDocPath);
        }

        private void DeleteFieldsRefInMyFields(string fieldName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            string xPath = string.Format("/xsd:schema/xsd:element/xsd:complexType/xsd:sequence/xsd:element[@ref='my:{0}']", fieldName);
            XPathNavigator myFieldIt = xNav.SelectSingleNode(xPath, manager);
            myFieldIt.DeleteSelf();
            xsdDoc.Save(xsdDocPath);
        }

        private void DeleteFieldDefinRootElement(string fieldName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            string xPath = string.Format("/xsd:schema/xsd:element[@name='{0}']", fieldName);
            XPathNavigator myFieldIt = xNav.SelectSingleNode(xPath, manager);
            myFieldIt.DeleteSelf();
            xsdDoc.Save(xsdDocPath);
        }

        private void UpdateFieldDefinRootElement(string fieldName, string displayName, string xsdDocPath)
        {
            XmlDocument xsdDoc = new XmlDocument();
            xsdDoc.Load(xsdDocPath);
            XmlNamespaceManager manager = new XmlNamespaceManager(xsdDoc.NameTable);
            manager.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
            manager.AddNamespace("ma", "http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes");
            XPathNavigator xNav = xsdDoc.CreateNavigator();
            string xPath = string.Format("/xsd:schema/xsd:element[@name='{0}']/@ma:displayName", fieldName);
            XPathNavigator myFieldIt = xNav.SelectSingleNode(xPath, manager);
            myFieldIt.SetValue(displayName);
            xsdDoc.Save(xsdDocPath);
        }

        private Dictionary<string, string> ExtractXSD(SPWeb Web, SPContentType cType)
        {
            Dictionary<string, string> _targetXSDFiles = new Dictionary<string, string>();
            //Get ContentType

            string xsdURL = cType.ParentList.RootFolder.ServerRelativeUrl + "/" + cType.ResourceFolder.Name + "/template.xsn";
            string xsdTemp = @"C:\TempXsnFiles\" + cType.Id.ToString();
            SPFile m_file = Web.GetFile(xsdURL);
            if (m_file.Exists)
            {
                //Get XSN File Temp Location
                _targetXSDFiles.Add(xsdURL, xsdTemp);
                //Move XSD To Temp Location
                int size = 10 * 1024;
                using (Stream stream = m_file.OpenBinaryStream())
                {
                    Directory.CreateDirectory(xsdTemp);
                    string xsdTempLoaction = xsdTemp + "\\template.xsn";
                    using (FileStream fs = new FileStream(xsdTempLoaction, FileMode.Create, FileAccess.Write))
                    {
                        byte[] xsd_content = m_file.OpenBinary();
                        int nBytesRead = 0;
                        while ((nBytesRead = stream.Read(xsd_content, 0, xsd_content.Length)) > 0)
                        {
                            fs.Write(xsd_content, 0, nBytesRead);
                        }
                    }
                }
            }

            string cmdString = string.Format("expand \"{0}\" \"{1}\" -f:*", xsdTemp + "\\template.xsn", xsdTemp);
            string cmdResult = RunCommand(cmdString, _targetXSDFiles[xsdURL]);

            return _targetXSDFiles;
            //Replace xsd file
            //Package and Upload
        }

        private string RunCommand(string cmdString, string xsdDictory)
        {
            Process p = new Process();
            //启动DOS程序
            p.StartInfo.WorkingDirectory = xsdDictory;
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;//不用Shell启动
            p.StartInfo.RedirectStandardInput = true;//重定向输入
            p.StartInfo.RedirectStandardOutput = true;//重定向输出
            p.StartInfo.CreateNoWindow = true;//不显示窗口
            p.Start();//开始进程
            p.StandardInput.WriteLine(cmdString);// 向cmd.exe输入command
            p.StandardInput.WriteLine("exit");//结束
            p.WaitForExit(60000);//等等执行完成
            string outPutString = p.StandardOutput.ReadToEnd();// 得到cmd.exe的输出
            p.Close();
            return outPutString;
        }

        private void ExceptionLog(string errorMessage)
        {
            using (FileStream fs = new FileStream("c:\\sp_event_log.txt", FileMode.Append, FileAccess.Write))
            {
                using (StreamWriter swt = new StreamWriter(fs, System.Text.Encoding.GetEncoding("utf-8")))
                {
                    swt.WriteLine(errorMessage);
                }
            }
        }

        private string CreateListFile(string xsdTemp)
        {
            try
            {
                string listFilePath = Path.Combine(xsdTemp, "list.txt");
                string listContent = string.Empty;//文件内容
                listContent += ";*** Sample Source Code MakeCAB Directive file example \r\n"
                            + ";\r\n"
                            + ".OPTION EXPLICIT ; Generate errors\r\n "
                            + ".Set CabinetNameTemplate=template_xsn\r\n"
                            + ".set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory\r\n"
                            + ".Set CompressionType=MSZIP;** All files are compressed in cabinet files\r\n"
                            + ".Set UniqueFiles=\"OFF\"\r\n"
                            + ".Set Cabinet=on\r\n"
                            + ".Set DiskDirectory1=test\r\n"
                            + ";*** <the end>\r\n";
                DirectoryInfo xsdTempDI = new DirectoryInfo(xsdTemp);
                FileInfo[] fileInfos = xsdTempDI.GetFiles();
                foreach (FileInfo fileInfo in fileInfos)
                {
                    if (fileInfo.Name != "template.xsn" && fileInfo.Name != "list.txt")
                    {
                        listContent += string.Format("\"{0}\" \r\n", fileInfo.Name);
                    }
                }
                using (FileStream fs = new FileStream(listFilePath, FileMode.Create, FileAccess.Write))
                {
                    using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
                    {
                        sw.Write(listContent);
                        sw.Flush();
                    }
                }

                return listFilePath;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        private void UploadXSN(SPWeb Web, string FileUrl, string XSNLocation)
        {
            Web.Files.Add(FileUrl, GetXsnFileStream(XSNLocation + "\\test\\template_xsn"), true);
        }

        private byte[] GetXsnFileStream(string XSNLocation)
        {
            byte[] buf = new byte[100];
            List<byte> bytes = new List<byte>();
            using (FileStream fs = File.Open(XSNLocation, FileMode.Open, FileAccess.Read))
            {
                int offset = 0;
                int len = 0;
                while ((len = fs.Read(buf, offset, buf.Length)) > 0)
                {
                    CopyOneStreamToStream(buf, bytes);
                    buf = new byte[100];
                }
            }

            return bytes.ToArray();
        }

        private void CopyOneStreamToStream(byte[] byte1, List<byte> byte2)
        {
            foreach (byte bt in byte1)
            {
                byte2.Add(bt);
            }
        }
    }
}
